/*
    Copyright (C) 2009 Giacomo Spigler

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#include <cutil.h>
#include <cuda_runtime.h>


#include <cv.h>
#include <highgui.h>


#include "../standardmodel/cuda/standard.h"
#include "../standardmodel/cuda/gabor.h"



#define writebyte(a__, fp__) fwrite(&a__, sizeof(unsigned char), 1, fp__);
#define writeint(a__, fp__) fwrite(&a__, sizeof(int), 1, fp__);
#define writefloat(a__, fp__) fwrite(&a__, sizeof(float), 1, fp__);

#define readbyte(a__, fp__) fread(&a__, sizeof(unsigned char), 1, fp__);
#define readint(a__, fp__) fread(&a__, sizeof(int), 1, fp__);
#define readfloat(a__, fp__) fread(&a__, sizeof(float), 1, fp__);





  int w_host[NUMSCALES], h_host[NUMSCALES];

  IplImage *pyr[NUMSCALES];


  int *w_dev, *h_dev;


  unsigned char *pyr_dev;
  unsigned char *s1_dev[4];
  unsigned char *c1_dev[4];
  size_t pyr_dev_pitch;
  size_t c1_pitch;

  int nums2, n4, n8;
  unsigned char *patch4x4; //device
  unsigned char *patch8x8; //device

  unsigned char *s2_dev; //device
  size_t s2_pitch;


  unsigned char *c2_dev;
  unsigned char *c2_host;





void buildC2(const char *outdir, const char *lab, const char *inpdir, int st, int en) {
//("c2/train", "pos", "../TrainImages", 0, 349);

  IplImage *im;


  for(int i=st; i<=en; i++) {
    printf("%d/%d\n", i, en);

    char in[80], out[80];
    sprintf(in, "%s/%s-%d.pgm.png", inpdir, lab, i);
    sprintf(out, "%s/%s-%d.c2", outdir, lab, i);

    im=cvLoadImage(in);

    SetPyramid_0(im, pyr, pyr_dev, pyr_dev_pitch);
    ComputeS1_1(pyr_dev, s1_dev, w_host, h_host, w_dev, h_dev, pyr_dev_pitch,   pyr);
    ComputeC1_2(s1_dev, c1_dev, w_host, h_host, w_dev, h_dev, pyr_dev_pitch, c1_pitch,   pyr);
    ComputeS2_3(c1_dev, w_host, h_host, w_dev, h_dev, c1_pitch, s2_pitch, s2_dev, nums2, n4, n8, patch4x4, patch8x8,   pyr);
    ComputeC2_4(w_host, h_host, w_dev, h_dev, s2_pitch, s2_dev, nums2, c2_dev, c2_host,   pyr);


    FILE *fp=fopen(out, "w");

    writeint(nums2, fp);
    for(int i=0; i<nums2; i++) {
      writebyte(c2_host[i], fp);
    }

    fclose(fp);

  }




}






int main() {
  IplImage *im=cvLoadImage("t.png");


  #ifdef DEBUG
    unsigned int hTimer;
    cutCreateTimer(&hTimer);
    cutStartTimer(hTimer);
  #endif



  pyr[0]=cvCreateImage(cvSize(im->width, im->height), 8, 1);
  w_host[0]=im->width; h_host[0]=im->height;
  for(int i=1; i<NUMSCALES; i++) {
    pyr[i]=cvCreateImage(cvSize(pyr[i-1]->width/INVERSESCALERATIO, pyr[i-1]->height/INVERSESCALERATIO), 8, 1);

    w_host[i]=pyr[i]->width; h_host[i]=pyr[i]->height;
  }


  InitWidthsHeights(w_host, h_host, &w_dev, &h_dev);


  LoadS2Patches("s2.patch", &nums2, &n4, &n8, &patch4x4, &patch8x8);


  InitPyramidBuffer(pyr, &pyr_dev, s1_dev, c1_dev, &pyr_dev_pitch, &c1_pitch, &s2_dev, nums2, &s2_pitch, &c2_dev, &c2_host);

  #ifdef DEBUG
    cutStopTimer(hTimer);
    printf("Initialization time: %fms\n", cutGetTimerValue(hTimer));
  #endif



  printf("**** 1 ****\n");
  buildC2("c2/train", "pos", "../TrainImages", 0, 349);
  printf("**** 2 ****\n");
  buildC2("c2/train", "neg", "../TrainImages", 0, 319);
  printf("**** 3 ****\n");
  buildC2("c2/test", "pos", "../TrainImages", 350, 549);
  printf("**** 4 ****\n");
  buildC2("c2/test", "neg", "../TrainImages", 320, 499);










  printf("Last CUDA error: %s\n", cudaGetErrorString(cudaGetLastError()));


  cvNamedWindow("l", CV_WINDOW_AUTOSIZE);
  cvShowImage("l", pyr[0]);
  cvWaitKey(0);

  cvDestroyWindow("l");

  cvReleaseImage(&im);


  FreeAll(w_dev, h_dev, pyr_dev, s1_dev, c1_dev, patch4x4, patch8x8, s2_dev, c2_dev, c2_host);

  return 0;
}




